<h1 class="kf">The OSGi Service Tutorial</h1>

<h2 class="kf">Contents</h2>
<ol>
 <li><a href="#what_is">What is a service?</a>
 <li><a href="#what_isfactory">What is a service factory?</a>
 <li><a href="#what_for">What can services be used for?</a>
 <li><a href="#accessing">How are services accessed??</a>
 <li><a href="#release">Releasing services</a>
 <li><a href="#best">Best practices for accessing services</a>
 <li><a href="#white">The white-board model</a>
</ol>

<a name="what_is"></a>
<h2 class="kf">What is a service?</h2>

<div class="intro">
An OSGi service is a java object instance, <i>registered</i> into
an OSGi framework with a set of <i>properties</i>. Any java object can be registered as a service, but typically it implements a well-known interface.
</div>

<p>
The OSGi <a href="http://www.osgi.org/osgi_technology/download_specs.asp?section=2">R3 specification</a>, chapter 4.10 is highly recommended reading. Also, the javadoc for <a href="$(JAVADOC)/org/osgi/framework/BundleContext.html">BundleContext</a> contains lot of information.
</p>

<p>
The client of a service is always an OSGi bundle, i.e. a piece of java
code possible to start via the <a href="$(JAVADOC)/org/osgi/framework/BundleActivator.html">BundleActivator</a> interface.
</p>

<p>
Each bundle may register zero or more services. Each bundle may also use
zero or more services. There exists no limit on the number of services, more 
than the ones given by memory limits or java security permissions.
</p>

<p>
Both publishing/registering and usage of services can be restricted by using java security permissions.
</p>

<pre class="codeexample">
<div class="head">Registering a very simple object as a service</div>
Integer   i     = new Long(20);
Hashtable props = new Hashtable();
props.put("description", "This an long value");
bc.<a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)">registerService</a>(Long.class.getName(), i, props);
</pre>

<p>
<b>Note</b>: a service can also be registered as serveral interfaces. In this case, the object <i>must</i> implement all of the interfaces.
</p>

<a name="what_isfactory"></a>
<h2 class="kf">What is a service factory?</h2>

<div class="intro">
An OSGi service factory is a special class <a href="$(JAVADOC)/org/osgi/framework/ServiceFactory.html">ServiceFactory</a>, which
can create individual instances of service objects for <i>different</i> bundles.</div>

<p>
Sometimes a service needs to be differently configured depending on which 
bundle uses the service. For example, the log service needs to be able to
print the logging bundle's id, otherwise the log would be hard to read.
</p>
<p>
A service factory is registered in exactly the same way as a normal service, using <a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#registerService(java.lang.String, java.lang.Object, java.util.Dictionary)">registerService</a>, the only difference is an indirection step before the actual service object is handed out.
</p>

<p>
The client using the service need not, and should not, care if a service is 
generated by a factory or by a plain object.
</p>

<pre class="codeexample">
<div class="head">A simple service factory example</div>
  class LongFactory implements ServiceFactory {
    public Object getService(Bundle bundle, ServiceRegistration reg) { 
       // each bundle gets a Long with its own id
       return new Long(bundle.getBundleId());
    }
    void ungetService(Bundle bundle, ServiceRegistration reg, Object service) {
       // nothing needed in this case
    }
  }
  
  ServiceFactory factory = new LongFactory();
  bc.registerService(Long.class.getName(), factory, new Hashtable()); 
</pre>

<p>
<b>Note</b>: The framework will cache generated service objects. Thus, 
at most one service can be generated per client bundle.
</p>

<a name="what_for"></a>
<h2 class="kf">What can services be used for?</h2>

<p>
The service concept is a very general-purpose tool, but some examples are:
</p>
<ul>
 <li>Export functionality from a bundle to other bundles<br>
 <li>Import functionality from other bundles<br>
 <li>Register listeners for events from other bundles<br>
 <li>Expose external devices, such as UPnP devices or even hardware,
     to other OSGi bundles. See the <a href="$(JAVADOC)/org/osgi/service/device/package-summary.html">Device</a> and <a href="$(JAVADOC)/org/osgi/service/upnp/package-summary.html">UPnP</a> APIs
 <li>Bundle configuration, using the <a href="$(JAVADOC)/org/osgi/service/cm/package-summary.html">Configuration Manager</a>
</ul>

<p>
Generally, services is the preferred method bundles should use to communicate 
between each other.
</p>

<a name="accessing"></a>
<h2 class="kf">How are services accessed?</h2>

<div class="intro">
Services are always accessed via <i>ServiceReferences</i>, which uniquely
points to a <i>service object</i>.
</div>

To access a service, the following procedure must always be used (possibly wrapped by utility code):
<ol>
 <li>Get a <tt><a href="$(JAVADOC)/org/osgi/framework/ServiceReference.html">ServiceReference</a></tt>
 <li>Get the service object from the reference, using <tt><a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#getService(org.osgi.framework.ServiceReference)">BundleContext.getService()</a></tt>
</ol>

<tt>ServiceReference</tt> are typically retreived by:
<ol>
 <li>Explicit usage of <tt><a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#getServiceReferences(java.lang.String, java.lang.String)">BundleContext.getService()</a></tt><br/>
     This returns either the highest ranked service of the given class, or 
     <tt>null</tt>

 <li>Explicit usage of <tt><a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#getServiceReference(java.lang.String)">BundleContext.getServices()</a></tt><br/>
    This return the complete set of matching services, or <tt>null</tt>
 <li>Callback from a <tt><a href="$(JAVADOC)/org/osgi/framework/ServiceListener.html">ServiceListener</a></tt>
 <li>Using the utility class <tt><a href="$(JAVADOC)/org/osgi/util/tracker/ServiceTracker.html">ServiceTracker</a></tt>
</ol>

<p>
All cases, except the first, allow the client to specify a set of properties
that the service must fullfill. These properties are specified using LDAP <a href="$(JAVADOC)/org/osgi/framework/Filter.html">filters</a>. Zero or more service
references can match a given filter. 
</p>
<p>
A typical filter contains a class name and a set of properties. The example below matches a Http service having a "port" property equal to 80.
</p>
<pre class="codeexample">
<div class="head">An LDAP filter string</div>
(&(objectclass=org.osgi.service.http.HttpService)(port=80))
</pre>

<p>
As soon as a ServiceReference is available, the service object can be accessed
using a cast:
</p>
<pre class="codeexample">
  HttpService http = (HttpService)bc.getService(sr);
</pre>

<p>
After this, the service object can be accessed as any other java object. Actually, it <b>is</b> a fully normal java object, more exact, it is the same object as the bundle registering the service created.
</p>

<a name="release"></a>
<h2 class="kf">Releasing services</h2>
<p>
As soon as the service isn't needed anymore, the client should <b>release</b>
the service by calling the <a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#ungetService(org.osgi.framework.ServiceReference)">BundleContext.ungetService()</a> method.
</p>

<pre class="codeexample">
  bc.ungetService(sr);
</pre>

<p>
All services are <b>automatically</b> released when the client bundles stops. 
No special service cleanup is needed in BundleActivator.stop().
</p>

<p>
Note that service should only be released when <b>really</b> unused. Some
services may keep a state for each using bundle, and releasing the service
will release this state, which may, or may not, be the intention. Each service
documentation must be consulted. An example of this is the <a href="$(JAVADOC)/org/osgi/service/http/HttpService.html">HttpService</a>, which
will remove all servlets and resources from itself when a client releases
the HttpService.
</p>

<p>
Some special words are needed when using service listeners. A listener
will get a <a href="$(JAVADOC)/org/osgi/framework/ServiceEvent.html#UNREGISTERING">ServiceEvent.UNREGISTERING</a> event when a service is in the process
of being unregistering from the framework.
</p>

<p>
While in this UNREGISTERING listener, the <tt>getService()</tt> call should
<b>not</b> be expected to return a valid service object. In fact, the expected value
is <tt>null</tt>, even if the spec is a bit vague on this. The OSGi reference
implementation does however return <tt>null</tt> in this case.
</p>

<a name="best"></a>
<h2 class="kf">Best practices for accessing OSGi services</h2>

<div class="intro">
OSGi services must always be considered volatile, and may disappear or become
unusable at <t>any time</t>.
</div>

<p>
Suggested practices:
</p>
<ul>
 <li>Always <b>expect RuntimeException</b> when calling a service<br>
     A service may fail at any time, similar to RMI based code. The recommended
     exception an unsuable service should throw is <tt>IllegalStateException</tt>
     This
     does <b>not</b> mean that a try/catch block should be made on each
     service call, rather that the code must be prepared to handle such
     exceptions on a higher level.

 <li>Use the <b><a href="#white">white-board model</a></b><br>
     If possible, construct your code so users of your bundle functionality
     can participate by registering services, instead of getting services.
     It's much easier to register a service, than to get it. Thus, if you 
     want to make life easier for clients, go for the white-board model.

 <li>Use <b>listeners</b><br>
     <a href="$(JAVADOC)/org/osgi/framework/ServiceListener.html">ServiceListener</a> and <a href="$(JAVADOC)/org/osgi/util/tracker/ServiceTracker.html">ServiceTracker</a> provide various levels of automation for getting services.

 <li>Use the declarative <b>ServiceBinder</b><br>
     The <a href="http://gravity.sourceforge.net/servicebinder/">ServiceBinder</a> by Cervantes/Hall provide a framework for cases where it's possible
     to declare service dependecies in XML.

</ul>


Consider the bad-styled, but common, code:
<pre class="codeexample">
<div class="head"><a name="ex_bad"></a>Bad code example</div>
01: ServiceReference sr  =  bc.<a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#getServiceReference(java.lang.String)">getServiceReference</a>(HttpService.class.getName());
02: HttpService http     = (HttpService)bc.<a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#getService(org.osgi.framework.ServiceReference)">getService</a>(sr);
03: http.registerServlet(....)
</pre>

Three things can fail, one for each line!<br>
<ol>
 <li>The ServiceReference can be <tt>null</tt> if no HttpService is registered,
     resulting in <tt>NullPointerException</tt> on line 2.
 <li>The http service object cannot be get, due to missing permissions,
     possible timing issues if the http unregisters between lines 1 and 2, 
     causing <tt>NullPointerException</tt> on line 3.
 <li>The http service may have become unusable, resulting in any 
     <tt>RuntimeException</tt> subclass, most likely <tt>IllegalStateException</tt> on
    line 3.
</ol>

<p>
Additionally, the code above does not handle the case where more than one service is registered and actions should be taken on each of them.
</p>

<p>
The NPE problems can be naively avoided by adding conditionals:
</p>

<pre class="codeexample">
01: ServiceReference sr  =  bc.getServiceReference(HttpService.class.getName());
02: if(sr != null) {
03:   HttpService http = (HttpService)bc.getService(sr);
04:   if(http != null) {
05:     http.registerServlet(....)
06:   }
07: }
</pre>

<p>
This approach quickly becomes very cumbersome, and also creates an undesirable
start order problem, since the HttpService must be available when the code is
run.
</p>

<p>
By using a service listener, the code can avoid the first ServiceReference 
<tt>null</tt> problem:
</p>
<pre class="codeexample">
<div class="head"><a name="ex_listener"></a>Using a service listener</div>
01: ServiceListener sl = new <a href="$(JAVADOC)/org/osgi/framework/ServiceListener.html">ServiceListener</a>() {
02:   public void ServiceChanged(<a href="$(JAVADOC)/org/osgi/framework/ServiceEvent.html">ServiceEvent</a> ev) {
03:      ServiceReference sr = ev.getServiceReference();
04:      switch(ev.getType()) {
05:        case <a href="$(JAVADOC)/org/osgi/framework/ServiceEvent.html#REGISTERED">ServiceEvent.REGISTERED</a>:
06:          {
07:             HttpService http = (HttpService)bc.getService(sr);
08:             http.registerServlet(...);
09:          }
10:          break;
11:        default:
12:          break;
13:      }
14:   }
15: };
16:
17: String filter = "(objectclass=" + HttpService.class.getName() + ")";
18: try {
19:   bc.<a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#addServiceListener(org.osgi.framework.ServiceListener)">addServiceListener</a>(sl, filter);
20: } catch (<a href="$(JAVADOC)/org/osgi/framework/InvalidSyntaxException.html">InvalidSyntaxException</a> e) { 
21:   e.printStackTrace(); 
22: }
</pre>
<p>
The possible RuntimeException when actually calling the service (line 8) is handled by the framework event delivery code, so if no special handling is needed in the client code, nothing needs to be done.
</p>

<p>
There's still one problem -- if all HttpServices already had been registered, the listener above would not be called until the HttpServices were restarted. A small trick solves this: Manually construct REGISTERED ServiceEvents and call the
listener:
</p>
<pre class="codeexample">
<div class="head"><a name="ex_manualevents"></a>Construct ServiceEvents - contd. from above</div>
18: try {
19:   bc.<a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#addServiceListener(org.osgi.framework.ServiceListener)">addServiceListener</a>(sl, filter);
20:   ServiceReference[] srl = bc.<a href="$(JAVADOC)/org/osgi/framework/BundleContext.html#getServiceReferences(java.lang.String, java.lang.String)">getServiceReferences</a>(null, filter);
21:   for(int i = 0; srl != null && i < srl.length; i++) {
22:     sl.serviceChanged(new ServiceEvent(ServiceEvent.REGISTRED,
23:                                      srl[i]));
24:   }
25: } catch (<a href="$(JAVADOC)/org/osgi/framework/InvalidSyntaxException.html">InvalidSyntaxException</a> e) { 
26:   e.printStackTrace(); 
27: }
</pre>

<p>
Now the number of lines has grown from three to 25+. Which may be OK if this
is a one-time operation. But if continuous use of a service is intended, it's easier to use a ServiceTracker:
</p>

<pre class="codeexample">
<div class="head"><a name="ex_tracker"></a>ServiceTracker example</div>
01: <a href="$(JAVADOC)/org/osgi/util/tracker/ServiceTracker.html">ServiceTracker</a> logTracker = new ServiceTracker(bc, <a href="$(JAVADOC)/org/osgi/service/log/LogService.html">LogService</a>.class.getName(), null);
02: logTracker.open();
03: ((LogService)logTracker.getService()).doLog(...); 
</pre>

<p>
The tracker guarantees to hold all currently available services, but may naturally return <tt>null</tt> if no services are available. This is often OK, since
the code need to be prepared for RuntimeException anyway.
</p>
<p>
The down-side of this approach is the continuous and annoying usage of casting to get the desired object. Wrapping this in a single utility method can ease 
usage a bit:
</p>

<pre class="codeexample">
01: ServiceTracker logTracker;
02:
03: void init() {
04:   logTracker = new ServiceTracker(bc, <a href="$(JAVADOC)/org/osgi/service/log/LogService.html">LogService</a>.class.getName(), null);
05: }
06:
07: LogService getLog() {
08:   return (LogService)logTracker.getService();
09: }
10: 
11: void test() {
12:   getLog().doLog(...);
13: }
</pre>

<a name="white"></a>
<h2 class="kf">The white-board model</h2>

<div class="intro">
"Don't call getService(), call registerService() instead!"
</div>

<p>
Consider the HttpService case. All clients must constantly monitor the
framework in some way to add its servlet(s) to the web server. 
This requires at least the amount of code examplified above, and even this
doesn't completely guard against timing problems.
</p>
<p>
Additionally, the Http service must provide special methods for 
adding and removing servlets, and maintain an internal list of added servlets.
This adds complexity both to the API and to the internal server code.
</p>

<p>
This is a very common scenario -- some kind of callbacks/listeners are needed
and the server needs to keep track of all available listeners.
</p>
<p>
<i>The OSGi framework already provides exactly this functionality.</i>
<p>

<p>
Thus, an alternative and much better approach is to let the 
client <b>register its servlets into the framework</b>, and let the http
 server use the framework list instead of an internal list.
</p>


<pre class="codeexample">
<div class="head">Servlet client</div>
01: class MyServlet extends HttpServlet {
02:  ...
03: }
04: 
05: HttpServlet servlet = new MyServlet();
06: Hashtable   props   = new Hashtable();
07: props.put("alias",  "/servlets/foo"); // desired http alias
08: ServiceRegistration reg = 
09:   bc.registerService(HttpServlet.class.getName(), servlet, props);
</pre>

<p>
The client needn't do anything more. If the servlet need to be removed, 
it is simply unregistered from the framework.
</p>
<pre class="codeexample">
10: reg.unregister();
</pre>
<p>
The new, improved http server would monitor the framework for all services 
being HttpServlets, and use the "alias" property to set the alias.
</p>

<p>
Below is a minimalistic wrapper for the existing http service: (a complete class doing this can be found in the <a href="https://github.com/knopflerfish/knopflerfish.org/tree/master/osgi/bundles/http/httpconsole/src/org/knopflerfish/bundle/httpconsole/HttpWrapper.java">Http Console</a> example code.
</p>

<pre class="codeexample">
<div class="head">HttpService wrapper</div>
  void open() {
    httpTracker = new ServiceTracker(bc, HttpService.class.getName(), null);
    httpTracker.open();

    ServiceListener sl = new ServiceListener() {
	public void serviceChanged(ServiceEvent ev) {
	  ServiceReference sr = ev.getServiceReference();
	  switch(ev.getType()) {
	  case ServiceEvent.REGISTERED:
	    {
              registerServlet(sr);
	    }
	    break;
	  case ServiceEvent.UNREGISTERING:
	    {
              unregisterServlet(sr);
	    }
	    break;
	  }
	}
      };
    
    String filter = "(objectclass=" + HttpServlet.class.getName() + ")";
    try {
      bc.addServiceListener(sl, filter);
      ServiceReference[] srl = bc.getServiceReferences(null, filter);
      for(int i = 0; srl != null && i < srl.length; i++) {
	sl.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED,
					   srl[i]));
      }
    } catch (InvalidSyntaxException e) { 
      e.printStackTrace(); 
    }
  }
  
  void registerServlet(ServiceReference sr) {
    HttpServlet servlet = (HttpServlet)bc.getService(sr);
    String alias        = (String)sr.getProperty("alias");
    
    Object[] httplist = httpTracker.getServices();
    
    for(int i = 0; httplist != null && i < httplist.length; i++) {
      HttpService http = (HttpService)httplist[i];
      try {
	Hashtable props = new Hashtable();
	http.registerServlet(alias, servlet, props, null);
      } catch (Exception e) {
	e.printStackTrace();
      }
    }
  }
  
  void unregisterServlet(ServiceReference sr) {
    String alias        = (String)sr.getProperty("alias");
    
    Object[] httplist = httpTracker.getServices();
    
    for(int i = 0; httplist != null && i < httplist.length; i++) {
      HttpService http = (HttpService)httplist[i];
      try {
	http.unregister(alias);
      } catch (Exception e) {
	e.printStackTrace();
      }
      bc.ungetService(sr);
    }
  }

</pre>
